import logging

from protorpc import messages
from protorpc import message_types
from protorpc import remote
from protorpc.wsgi import service

from models import perms
from proto_rpc_play.util import yaml_utils


class YamlMessage(messages.Message):
    """An object in YAML format."""
    yaml = messages.StringField(1, required=True)


class PermissionType(messages.Message):
    column = messages.StringField(1, required=True)
    read = messages.StringField(2, repeated=True)
    write = messages.StringField(3, repeated=True)


class Permission(messages.Message):
    model_name = messages.StringField(1, required=True)
    default = messages.MessageField(PermissionType, 2, required=True)
    columns = messages.MessageField(PermissionType, 3, repeated=True)


class Permissions(messages.Message):
    permissions = messages.MessageField(Permission, 1, repeated=True)


def permission_rpc_to_ndb_mapper(permission_rpc):
    default = perms.PermissionType(column=permission_rpc['default']['column'],
                                   read=permission_rpc['default']['read'],
                                   write=permission_rpc['default']['write'])
    columns = []
    for column in permission_rpc['columns']:
        columns.append(perms.PermissionType(column=column['column'],
                                            read=column['read'],
                                            write=column['write']))

    perm = perms.Permission(model_name=permission_rpc['model_name'],
                            default=default,
                            columns=columns)

    return perm


def permission_ndb_to_rpc_mapper(permission_ndb):
    default = PermissionType(column=permission_ndb.default.column,
                             read=permission_ndb.default.read,
                             write=permission_ndb.default.write)
    columns = []
    for column in permission_ndb.columns:
        columns.append(PermissionType(column=column.column,
                                      read=column.read,
                                      write=column.write))

    permission = Permission(model_name=permission_ndb.model_name,
                            default=default,
                            columns=columns)

    return permission


class PermissionService(remote.Service):
    @remote.method(Permission, message_types.VoidMessage)
    def post_permission(self, request):
        # map rpc request to model

        perm = permission_rpc_to_ndb_mapper(request)
        perm.put()

        return message_types.VoidMessage()

    # TODO(raulg): - add the ability for this to get model based on key/model name
    @remote.method(message_types.VoidMessage, Permission)
    def get_permission(self, request):
        # get the current permissions

        return Permission(model_name='Dog',
                          default=PermissionType(column='__default',
                                                 read=['doug'],
                                                 write=['doug']))


class PermissionsService(remote.Service):
    @remote.method(message_types.VoidMessage, Permissions)
    def get_permissions(self, request):
        # get the current permissions
        perm_models = perms.Permission.query().fetch()

        permissions = []
        for perm in perm_models:
            permission = permission_ndb_to_rpc_mapper(perm)
            permissions.append(permission)

        return Permissions(permissions=permissions)

    @remote.method(message_types.VoidMessage, YamlMessage)
    def get_permissions_yaml(self, request):
        perm_models = perms.Permission.query().fetch()

        permissions = []
        for perm in perm_models:
            permissions.append(perm.to_dict())

        yaml = yaml_utils.Dump(permissions)
        return YamlMessage(yaml=yaml)

    @remote.method(Permissions, message_types.VoidMessage)
    def post_permissions(self, request):
        permissions = request.permissions

        for permission in permissions:
            perm = permission_rpc_to_ndb_mapper(permission)
            perm.put()

        return message_types.VoidMessage()

    @remote.method(YamlMessage, message_types.VoidMessage)
    def post_permissions_yaml(self, request):
        yaml = request.yaml

        permissions = yaml_utils.Load(yaml)
        for permission in permissions:
            perm = permission_rpc_to_ndb_mapper(permission)
            perm.put()

        return message_types.VoidMessage()


# The application
app = service.service_mappings([
    ('/PermissionService.*', PermissionService),
    ('/PermissionsService.*', PermissionsService),
])
